//
//  PolygonObject.m
//  Box2DProject
//
//  Created by Thi Huynh on 9/12/12.
//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
//

#import "PolygonObject.h"
#import "PRRatcliffTriangulator.h"


@interface PolygonObject (privateMethods)

/**
 Recalculate the texture coordinates. Called when setTexture is called.
 */
-(void) calculateTextureCoordinates;
-(void) setPoints: (NSArray *) points;

@end

@implementation PolygonObject

@synthesize triangulator            = _triangulator;
@synthesize body                    = _body;
@synthesize isDestroyed             = _isDestroyed;
@synthesize isEndSlice              = _isEndSlice;
@synthesize isStartSlice            = _isStartSlice;
@synthesize startSlicePoint         = _startSlicePoint;
@synthesize endSlicePoint           = _endSlicePoint;
@synthesize centroid                = _centroid;
@synthesize fileName                = _fileName;
@synthesize shapeVertices           = _shapeVertices;
@synthesize sliceTime               = _sliceTime;


#pragma mark - init section
- (id)initWithFileName:(NSString*)name body:(b2Body*)body vertices:(b2Vec2*)vertices verticeCnt:(int)verticeCnt destroyed:(BOOL)destroyed
{
    _fileName = name;
    _shapeVertices = vertices;
    _vertexCount = verticeCnt;
    NSAssert(name != nil, @"Invalid filename for sprite");
    NSMutableArray *points = [NSMutableArray arrayWithCapacity:_vertexCount];
    for(int i = 0; i < _vertexCount; i++) 
    {
        CGPoint p = ccp(_shapeVertices[i].x * PTM_RATIO, _shapeVertices[i].y * PTM_RATIO);
        [points addObject:[NSValue valueWithCGPoint:p]];
    }
    _body = body;
    _body->SetUserData(self);
    if ((self = [self initWithPoints:points andFileName:name]))
    {
        _isStartSlice = NO;
        _isEndSlice = NO;
        _startSlicePoint.SetZero();
        _endSlicePoint.SetZero();
        _isDestroyed = destroyed;
        
    }
    return self;
}

- (id)initWithFileName:(NSString*)name 
                  body:(b2Body*)body 
             destroyed:(BOOL)destroyed
{
    _fileName = name;
    NSAssert(name != nil, @"Invalid filename for sprite");
    NSMutableArray *points = [NSMutableArray arrayWithCapacity:_vertexCount];
    for(int i = 0; i < _vertexCount; i++) 
    {
        CGPoint p = ccp(_shapeVertices[i].x * PTM_RATIO, _shapeVertices[i].y * PTM_RATIO);
        [points addObject:[NSValue valueWithCGPoint:p]];
    }
    _body = body;
    _body->SetUserData(self);
    if ((self = [self initWithPoints:points andFileName:name]))
    {
        _isStartSlice = NO;
        _isEndSlice = NO;
        _startSlicePoint.SetZero();
        _endSlicePoint.SetZero();
        _isDestroyed = destroyed;
       
    }
    return self;
}

- (id)initWithPoints: (NSArray *) polygonPoints 
         andFileName:(NSString *)name 
{
    return [self initWithPoints:polygonPoints 
                    andFileName:name 
              usingTriangulator:[[[PRRatcliffTriangulator alloc] init] autorelease]];
}

- (id)initWithPoints:(NSArray *)polygonPoints 
         andFileName:(NSString *)name 
   usingTriangulator: (id<PRTriangulator>) polygonTriangulator 
{
    if( (self=[super initWithFile:name])) 
    {
        //setting for sprite texture
        ccTexParams texParams = { GL_NEAREST, GL_NEAREST, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE };
        [texture_ setTexParameters: &texParams];
        [self updateBlendFunc];
        [self calculateTextureCoordinates];
        //set anchor point base on the center of body
        // gets the center of the polygon
        _centroid = self.body->GetLocalCenter();
        self.anchorPoint = ccp(0,0);//ccp(_centroid.x * PTM_RATIO / texture_.contentSize.width, 
                               //_centroid.y * PTM_RATIO / texture_.contentSize.height);
        //set shader
        self.shaderProgram = [[CCShaderCache sharedShaderCache] programForKey:kCCShader_PositionTexture];
        //set triangulator
        self.triangulator = polygonTriangulator;
        //set polygon points
        [self setPoints:polygonPoints];
	}
	return self;
}

/**
 Returns an autoreleased polygon.  Default triangulator is used (Ratcliff's).
 */
+ (id) filledPolygonWithPoints: (NSArray *) polygonPoints andFileName:(NSString *)name
{
    return [[[PolygonObject alloc] initWithPoints:polygonPoints andFileName:name] autorelease];
}

/**
 Returns an autoreleased filled poly with a supplied triangulator.
 */
+ (id) filledPolygonWithPoints:(NSArray *)polygonPoints 
                   andFileName:(NSString *)name 
             usingTriangulator:(id<PRTriangulator>) polygonTriangulator
{
    return [[[PolygonObject alloc] initWithPoints:polygonPoints andFileName:name usingTriangulator:polygonTriangulator] autorelease];
    return self;
}

- (id)initPolygonWith:(b2World*)world fileName:(NSString*)name 
{
    return  nil;
}


- (id)initPolygonWith:(b2World*)world fileName:(NSString*)name andPos:(CGPoint )pos;
{
    return nil;
}

#pragma mark - draw section
/*
 * Overload draw method in CCNode to draw polygon sprite with texture
 */

-(void) draw
{
    CC_NODE_DRAW_SETUP();
    
    ccGLBindTexture2D(texture_.name );
    
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    
    ccGLBlendFunc( blendFunc.src, blendFunc.dst);
	
    ccGLEnableVertexAttribs(kCCVertexAttribFlag_Position | kCCVertexAttribFlag_TexCoords );
    
    glVertexAttribPointer(kCCVertexAttrib_Position, 2, GL_FLOAT, GL_FALSE, 0, areaTrianglePoints);
    glVertexAttribPointer(kCCVertexAttrib_TexCoords, 2, GL_FLOAT, GL_FALSE, 0, textureCoordinates);
	
    glDrawArrays(GL_TRIANGLES, 0, _areaTrianglePointCount);
}

-(void) updateBlendFunc 
{
	// it's possible to have an untextured sprite
	if( !texture_ || ! [texture_ hasPremultipliedAlpha] ) 
    {
		blendFunc.src = GL_SRC_ALPHA;
		blendFunc.dst = GL_ONE_MINUS_SRC_ALPHA;
		//[self setOpacityModifyRGB:NO];
	} 
    else 
    {
		blendFunc.src = CC_BLEND_SRC;
		blendFunc.dst = CC_BLEND_DST;
		//[self setOpacityModifyRGB:YES];
	}
}

-(void) setBlendFunc:(ccBlendFunc)blendFuncIn {
	blendFunc = blendFuncIn;
}

-(ccBlendFunc) blendFunc 
{
	return blendFunc;
}


#pragma mark - private methods

-(void) calculateTextureCoordinates 
{
    for (int j = 0; j < _areaTrianglePointCount; j++) 
    {
        textureCoordinates[j] = ccpMult(areaTrianglePoints[j], 1.0f/texture_.pixelsWide*CC_CONTENT_SCALE_FACTOR());
        textureCoordinates[j].y = 1 - textureCoordinates[j].y;
    }
}

/*
* Set point from CGPOINT array to triangulate array
*/
-(void) setPoints: (NSArray *) points 
{
    if (areaTrianglePoints)
        free(areaTrianglePoints);
    if (textureCoordinates)
        free(textureCoordinates);
    
    NSArray *triangulatedPoints = [_triangulator triangulateVertices:points];
    
    _areaTrianglePointCount = [triangulatedPoints count];
    areaTrianglePoints = (CGPoint *) malloc(sizeof(CGPoint) * _areaTrianglePointCount);
    textureCoordinates = (CGPoint *) malloc(sizeof(CGPoint) * _areaTrianglePointCount);
    
    for (int i = 0; i < _areaTrianglePointCount; i++)
        areaTrianglePoints[i] = [[triangulatedPoints objectAtIndex:i] CGPointValue];
    
    [self calculateTextureCoordinates];
    
}

#pragma mark - Public Methods
- (b2Body*)createBodyWith:(b2World*)world 
                     position:(b2Vec2)position 
                     rotation:(float)rotation 
                     vertices:(b2Vec2*)vertices 
                  vertexCount:(int32)count 
                      density:(float)density 
                     friction:(float)friction 
                  restitution:(float)restitution
{
    b2BodyDef bodyDef;
    bodyDef.type = b2_dynamicBody;
    bodyDef.position = position;
    bodyDef.angle = rotation;
    b2Body *body = world->CreateBody(&bodyDef);
    
    b2FixtureDef fixtureDef;
    fixtureDef.density = density;
    fixtureDef.friction = friction;
    fixtureDef.restitution = restitution;
    fixtureDef.filter.categoryBits = 0x0001;
    fixtureDef.filter.maskBits = 0x0001;
    //fixtureDef.isSensor = YES;
    
    b2PolygonShape shape;
    shape.Set(vertices, count);
    fixtureDef.shape = &shape;
    body->CreateFixture(&fixtureDef);
    
    return body;
}
/*
 * Overloaded setPosition method to include the Box2D body in the position adjustment
 */
- (void)setPosition:(CGPoint)position
{
    [super setPosition:position];
    if(_body)
        _body->SetTransform(b2Vec2(position.x/PTM_RATIO,position.y/PTM_RATIO), _body->GetAngle());
}

/*
 * Sets the category and mask bits to collide with itself
 */
- (void)activateCollisions
{
    b2Fixture *fixture = _body->GetFixtureList();
    b2Filter filter = fixture->GetFilterData();
    filter.categoryBits = 0x0001;
    filter.maskBits = 0x0001;
    fixture->SetFilterData(filter);
}

/*
 * Sets the category and mask bits to not collide with anything
 */
- (void)deactivateCollisions
{
    b2Fixture *fixture = _body->GetFixtureList();
    b2Filter filter = fixture->GetFilterData();
    filter.categoryBits = 0;
    filter.maskBits = 0;
    fixture->SetFilterData(filter);
}

-(void) dealloc 
{
    [super dealloc];
	free(areaTrianglePoints);
	free(textureCoordinates);
	//[texture release]; 
    //texture = nil;
    [_triangulator release]; 
    _triangulator = nil;
}

@end
